#ifndef __LOGGER_H__
#define __LOGGER_H__ 
#include <cstdio>
#include <iostream>
#include <stdarg.h>
#include <vector>
#include <string>
#include <functional>
#include <unordered_map>
#include <type_traits>
#include <atomic>
#include "Looper.hpp"
#include "Message.hpp"
#include "Utile.hpp"
#include "Level.hpp"
#include "Skip.hpp"
#include "Formatter.hpp"

namespace ssslog
{
    class SyncLogger;
    class AsyncLogger;
    //建造者模式建造日志系统
    class Logger
    {
    public:
        Logger(const std::string& name, 
            Formatter::ptr formatter,
            std::vector<LogSink::ptr>& sinks, 
            LogLevel::value level = LogLevel::value::DEBUG)
            :_name(name), _level(level), _formatter(formatter),
            _sinks(sinks.begin(), sinks.end()) 
            {}

        using ptr = std::shared_ptr<Logger>;
        std::string LoggerName() { return _name; }
        LogLevel::value LoggerLevel() { return _level; }
        void Debug(const char* file, size_t line, const char* fmt, ...) 
        {
            if (ShouldLog(LogLevel::value::DEBUG) == false) return;
            va_list al;
            va_start(al, fmt);
            Log(LogLevel::value::DEBUG, file, line, fmt, al);
            va_end(al);
        }
        void Info(const char *file, size_t line, const char *fmt, ...) 
        {
            if (ShouldLog(LogLevel::value::INFO) == false) return ;
            va_list al;
            va_start(al, fmt);
            Log(LogLevel::value::INFO, file, line, fmt, al);
            va_end(al);
        }
        void Warn(const char *file, size_t line, const char *fmt, ...) 
        {
            if (ShouldLog(LogLevel::value::WARN) == false) return ;
            va_list al;
            va_start(al, fmt);
            Log(LogLevel::value::WARN, file, line, fmt, al);
            va_end(al);
        }
        void Error(const char *file, size_t line, const char *fmt, ...) 
        {
            if (ShouldLog(LogLevel::value::ERROR) == false) return ;
            va_list al;
            va_start(al, fmt);
            Log(LogLevel::value::ERROR, file, line, fmt, al);
            va_end(al);
        }
        void Fatal(const char *file, size_t line, const char *fmt, ...) 
        {
            if (ShouldLog(LogLevel::value::FATAL) == false) return;
            va_list al;
            va_start(al, fmt);
            Log(LogLevel::value::FATAL, file, line, fmt, al);
            va_end(al);
        }
        std::string& name() {return _name;}
    private:
        bool ShouldLog(LogLevel::value level) { return level >= _level; }
        void Log(LogLevel::value level, const char* file, size_t line, const char* fmt, va_list al) 
        {
            char* buf = nullptr;
            std::string mes;
            int len = vasprintf(&buf, fmt, al);
            if (len < 0) mes = "格式化日志消息失败！！";
            else 
            {
                mes.assign(buf, len);
                free(buf);
            }
            Message mage(_name, file, line, std::move(mes), level);
            std::stringstream ss;
            _formatter->Format(ss, mage);
            LogIt(std::move(ss.str()));
        }
        virtual void LogIt(const std::string &mes) = 0;
        
    protected:
        std::mutex _mtx;
        std::string _name;
        Formatter::ptr _formatter;
        std::atomic<LogLevel::value> _level;
        std::vector<LogSink::ptr> _sinks;
    };
    //建造日志系统
    class Build
    {
    public:
        enum Type
        {
            LOGGER_SYNC = 0, // 同步
            LOGGER_ASYNC     // 异步
        };
        using ptr = std::shared_ptr<Build>;
        Build() : _level(LogLevel::value::DEBUG),
                  _logger_type(Type::LOGGER_SYNC)
        {}
        void BuildLoggerName(const std::string &name) { _logger_name = name; }
        void BuildLoggerLevel(LogLevel::value level) { _level = level; }
        void BuildLoggerType(Type type) { _logger_type = type; }
        void BuildFormatter(const std::string pattern) { _formatter = std::make_shared<Formatter>(pattern); }
        void BuildFormatter(const Formatter::ptr &formatter) { _formatter = formatter; }
        template <typename SinkType, typename... Args>
        void BuildSink(Args &&...args)
        {
            auto sink = SinkFactory::Create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(sink);
        }

        virtual Logger::ptr build() = 0;

    protected:
        Type _logger_type;
        std::string _logger_name;
        LogLevel::value _level;
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
        AsyncType _async_type;
    };
    
    //同步日志服务
    class SyncLogger : public Logger
    {
    public:
        using ptr = std::shared_ptr<SyncLogger>;
        SyncLogger(const std::string &name,
                   Formatter::ptr formatter,
                   std::vector<LogSink::ptr> &sinks,
                   LogLevel::value level = LogLevel::value::DEBUG) 
                   :Logger(name, formatter, sinks, level)
                    {
                        std::cout << LogLevel::toString(level) << " 同步日志器: " << name << "创建成功...\n";
                    }

    private:
        virtual void LogIt(const std::string& mes)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            if (_sinks.empty()) return;
            for (auto &it : _sinks)
            {
                it->Log(mes.c_str(), mes.size());
            }
        }
    };
    //异步日志服务
    class AsyncLogger : public Logger
    {
    public:
        using ptr = std::shared_ptr<AsyncLogger>;
        AsyncLogger(const std::string& name,
                    LogLevel::value level,
                    Formatter::ptr& formatter,
                    std::vector<LogSink::ptr>& sinks,
                    AsyncType lopper_type) 
                    :Logger(name, formatter, sinks, level)
                    ,_lopper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::RealLog, this, std::placeholders::_1), lopper_type))
                    {
                        std::cout << LogLevel::toString(level) << "异步日志器: " << name << "创建成功...\n";
                    }
    private:
        //插入数据的
        virtual void LogIt(const std::string& mes)
        {
            _lopper->Push(mes.c_str(),mes.size());
        }
        //执行的函数
        void RealLog(Buffer& mes)
        {
            if (_sinks.empty()) return;
            for (auto& it : _sinks)
            {
                it->Log(mes.Begin(), mes.ReadBuff());
            }
        }

    private:
        AsyncLooper::ptr _lopper;
    };

    class LocalLoggerBuilder : public Build
    {
        public:
            Logger::ptr build() override
            {
                assert(!_logger_name.empty());//必须要有日志器名称
                if(_formatter.get() == nullptr)
                {
                    _formatter = std::make_shared<Formatter>();
                }
                if(_sinks.empty())
                {
                    BuildSink<StdoutSink>();
                }
                if(_logger_type == Type::LOGGER_ASYNC)
                {
                    //不做处理
                    //return std::make_shared<AsyncLogger>(_logger_name, _level, _formatter, _sinks, _async_type);
                }
                
                return std::make_shared<SyncLogger>(_logger_name,_formatter,_sinks,_level);
            }
    };

    
    class LoggerMangger
    {
    public:
        static LoggerMangger &GetInstance()
        {
            // 在c++11后，针对静态局部变量，编译器在编译的层面实现了线程安全
            // 当静态局部变量没有构造完成之前，其他线程进入就会阻塞
            static LoggerMangger eton;
            return eton;
        }

        void AddLogger(Logger::ptr& logger) // 添加日志器管理
        {
            if (HasLogger(logger->name()))
            {
                return; // 该日志器名称已经存在，不需要添加
            }
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->name(), logger));
        }

        bool HasLogger(const std::string &name) // 判断是否管理了指定名称的日志器
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return false;
            }
            return true;
        }

        Logger::ptr GetLogger(const std::string &name) // 获取日志器
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return Logger::ptr();
            }
            return it->second;
        }

        Logger::ptr RootLogger() { return _root_logger; }
        
    private:
        LoggerMangger()
        {
            // 注意这里不能用全局的日志器建造者，否则会导致死循环26*
            std::unique_ptr<Build> builder(new LocalLoggerBuilder());
            builder->BuildLoggerName("root");
            _root_logger = builder->build();
            _loggers.insert(std::make_pair("root", _root_logger));
        }

    private:
        std::mutex _mutex;        // 互斥锁
        Logger::ptr _root_logger; // 默认日志器
        std::unordered_map<std::string, Logger::ptr> _loggers;
    };

     class GlobalLoggerBuilder : public Build
     {
    public:
        Logger::ptr build()
        {
            assert(!_logger_name.empty()); // 必须要有日志器名称
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                BuildSink<StdoutSink>();
            }
            Logger::ptr logger;
            if (_logger_type == Type::LOGGER_ASYNC) 
                logger = std::make_shared<AsyncLogger>(_logger_name, _level, _formatter, _sinks, _async_type);
            else
                logger = std::make_shared<SyncLogger>(_logger_name, _formatter, _sinks, _level);
            LoggerMangger::GetInstance().AddLogger(logger);
             return logger;
        }
    };
    
}

#endif